package ua.simplecoding.kievhome.dao.query;

import org.apache.commons.lang.Validate;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import ua.simplecoding.kievhome.filter.*;

public abstract class AbstractCriteriaBuilder<Filter> implements ICriteriaBuilder<Filter> {

    private Class targetClass;
    private Session session;

    public AbstractCriteriaBuilder(Session session, Class targetClass) {
        Validate.notNull(session);
        Validate.notNull(session);
        this.targetClass = targetClass;
        this.session = session;
    }


    public Criteria buildCriteria(Filter filter) {
        Validate.notNull(filter);

        Criteria criteria = session.createCriteria(targetClass);

        buildFilterOptions(criteria, filter);

        IPaginableFilter paginableFilter = (IPaginableFilter)filter;
        if (paginableFilter != null && paginableFilter.getPageConfiguration() != null) {
            buildPagination(criteria, paginableFilter.getPageConfiguration());
        }

        ISortableFilter sortableFilter = (ISortableFilter)filter;
        if (sortableFilter != null && sortableFilter.getSortConfiguration() != null) {
            buildSorting(criteria, sortableFilter.getSortConfiguration());
        }

        return criteria;
    }

    private void buildPagination(Criteria criteria, PageConfiguration pageConfiguration) {
        if (pageConfiguration.getPageSize() != null) {
            criteria.setMaxResults(pageConfiguration.getPageSize());
            if (pageConfiguration.getPageNo() != null) {
                criteria.setFirstResult(pageConfiguration.getPageNo() * pageConfiguration.getPageSize());
            }
        }
    }

    protected void buildSorting(Criteria criteria, SortConfiguration sortConfiguration) {
        boolean isAscending = sortConfiguration.getSortOrder().equals(SortOrderEnum.ASC);

        for (SortFieldEnum sortFieldEnum : sortConfiguration.getSortFields()) {
            mapSortField(criteria, isAscending, sortFieldEnum);
        }
    }

    protected Order getOrder(boolean ascending, String s) {
        return ascending ? Order.asc(s) : Order.desc(s);
    }

    protected abstract void mapSortField(Criteria criteria, boolean ascending, SortFieldEnum sortFieldEnum);

    protected abstract void buildFilterOptions(Criteria filter, Filter criteria);

}
